package za.um.td.prototyping;

import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.InputHandler;
import com.jme.input.MouseInput;
import com.jme.intersection.TrianglePickResults;
import com.jme.math.Matrix4f;
import com.jme.math.Ray;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.scene.TriMesh;
import com.jme.scene.state.CullState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jmex.effects.ProjectedTextureUtil;
import com.jmex.terrain.TerrainPage;
import com.jmex.terrain.util.ImageBasedHeightMap;
import com.jmex.terrain.util.ProceduralSplatTextureGenerator;

/**
 * <code>TestProjectedTexture</code>
 *
 * @author Tyler Trussell
 */
public class TestProjectedTextureMouse extends SimpleGame {
    private static final Logger logger = Logger
            .getLogger(TestProjectedTextureMouse.class.getName());

	private TerrainPage terrain;

	private Texture projectedTexture1;

    boolean mouseIgnore = false;

    private TrianglePickResults results;

	public static void main( String[] args ) {
		TestProjectedTextureMouse app = new TestProjectedTextureMouse();
		app.setConfigShowMode(ConfigShowMode.AlwaysShow);
		app.start();
	}

    @Override
	protected void simpleUpdate() {

        /*
         * This really long section of Vector3f and Vector2f
         * and pick results is to find where you are pointing
         * with your mouse. It then saves the Vector3f of where
         * you are pointing to the variable "loc"
         */
        Vector2f screenPos = new Vector2f(MouseInput.get().getXAbsolute(), MouseInput.get().getYAbsolute());
        Vector3f startPoint = DisplaySystem.getDisplaySystem().getWorldCoordinates(screenPos, 0);
        Vector3f endPoint = DisplaySystem.getDisplaySystem().getWorldCoordinates(screenPos, 1);
        Ray ray = new Ray(startPoint, endPoint.subtract(startPoint));

        results.clear();
        rootNode.findPick(ray, results);

        Vector3f loc = new Vector3f();
        Vector3f[] vertex = new Vector3f[3];
        boolean foundMeshHit = false;
        for(int pickIndex = 0; pickIndex < results.getNumber(); pickIndex++)
        {
            TriMesh mesh = (TriMesh) results.getPickData(pickIndex).getTargetMesh();
            for (int j = 0; j < mesh.getTriangleCount(); j++)
            {
                mesh.getTriangle(j, vertex);

                foundMeshHit = (ray.intersectWhere(vertex[0].addLocal(mesh.getWorldTranslation()),
                    vertex[1].addLocal(mesh.getWorldTranslation()),
                    vertex[2].addLocal(mesh.getWorldTranslation()), loc));
                if(foundMeshHit)
                {

                    Vector3f newLoc = loc.clone();
                    newLoc.y += 20f;

                    Vector3f groundLoc = loc.clone();
                    groundLoc.y = terrain.getHeight(groundLoc);

                    ProjectedTextureUtil.updateProjectedTexture(projectedTexture1, 30.0f, 1.0f, 1.0f, 1000.0f, newLoc, groundLoc, new Vector3f(0,-1,0));
                }
            }
        }
	}

	protected void simpleInitGame()
    {
        input = new InputHandler();
        MouseInput.get().setCursorVisible(true);

        results = new TrianglePickResults();
        
		try {
            display.setTitle( "Mouse ProjectedTexture Test" );

			cam.getLocation().set( new Vector3f( 50, 50, 0 ) );
			cam.lookAt( new Vector3f(), Vector3f.UNIT_Y );

			CullState cs = display.getRenderer().createCullState();
			cs.setCullFace( CullState.Face.Back );
			cs.setEnabled( true );

			TextureState ts = display.getRenderer().createTextureState();

			//create terrain
			URL grayScale = TestProjectedTextureMouse.class.getClassLoader().getResource( "jmetest/data/texture/terrain.png" );
			ImageBasedHeightMap heightMap = new ImageBasedHeightMap( new javax.swing.ImageIcon( grayScale ).getImage() );
			Vector3f terrainScale = new Vector3f( .5f, .05f, .5f );
			terrain = new TerrainPage( "image icon", 33, (heightMap.getSize()) + 1, terrainScale, heightMap.getHeightMap() );
			terrain.setDetailTexture( 1, 16 );
			terrain.setModelBound( new BoundingBox() );
			terrain.updateModelBound();
			terrain.setLocalTranslation( new Vector3f( 0, 0, 0 ) );
			rootNode.attachChild( terrain );
			rootNode.setRenderState( cs );

			ProceduralSplatTextureGenerator pst = new ProceduralSplatTextureGenerator( heightMap );
			pst.addTexture( new javax.swing.ImageIcon( TestProjectedTextureMouse.class.getClassLoader().getResource(
					"jmetest/data/texture/grassb.png" ) ), -128, 0, 128 );
			pst.addTexture( new javax.swing.ImageIcon( TestProjectedTextureMouse.class.getClassLoader().getResource(
					"jmetest/data/texture/dirt.jpg" ) ), 0, 128, 255 );
			pst.addTexture( new javax.swing.ImageIcon( TestProjectedTextureMouse.class.getClassLoader().getResource(
					"jmetest/data/texture/highest.jpg" ) ), 128, 255, 384 );

			pst.addSplatTexture( new javax.swing.ImageIcon( TestProjectedTextureMouse.class.getClassLoader().getResource(
					"jmetest/data/texture/terrainTex.png" ) ), new javax.swing.ImageIcon( TestProjectedTextureMouse.class.getClassLoader().getResource(
					"jmetest/data/texture/water.png" ) ) );
			pst.createTexture( 512 );

			ts = display.getRenderer().createTextureState();
			ts.setEnabled( true );
			Texture t1 = TextureManager.loadTexture( pst.getImageIcon().getImage(), Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear, true );
			ts.setTexture( t1, 0 );

			t1.setApply( Texture.ApplyMode.Combine );
			t1.setCombineFuncRGB( Texture.CombinerFunctionRGB.Modulate );
			t1.setCombineSrc0RGB( Texture.CombinerSource.CurrentTexture );
			t1.setCombineOp0RGB( Texture.CombinerOperandRGB.SourceColor );
			t1.setCombineSrc1RGB( Texture.CombinerSource.PrimaryColor );
			t1.setCombineOp1RGB( Texture.CombinerOperandRGB.SourceColor );
			t1.setCombineScaleRGB( Texture.CombinerScale.One );

			//create a texture to use for projection
			projectedTexture1 = TextureManager.loadTexture(
                    TestProjectedTextureMouse.class.getClassLoader().getResource(
					"jmetest/data/images/Monkey.png" ),
                    Texture.MinificationFilter.Trilinear,
                    Texture.MagnificationFilter.Bilinear );

			ts.setTexture( projectedTexture1, 1 );

			//this is were we set the texture up for projection
            projectedTexture1.setMatrix(new Matrix4f());
            projectedTexture1.setWrap(Texture.WrapMode.BorderClamp );
            projectedTexture1.setEnvironmentalMapMode( Texture.EnvironmentalMapMode.EyeLinear );
            projectedTexture1.setApply( Texture.ApplyMode.Combine );
            projectedTexture1.setCombineFuncRGB( Texture.CombinerFunctionRGB.Add );
            projectedTexture1.setCombineSrc0RGB( Texture.CombinerSource.CurrentTexture );
            projectedTexture1.setCombineOp0RGB( Texture.CombinerOperandRGB.SourceColor );
            projectedTexture1.setCombineSrc1RGB( Texture.CombinerSource.Previous );
            projectedTexture1.setCombineOp1RGB( Texture.CombinerOperandRGB.SourceColor );
            projectedTexture1.setCombineScaleRGB( Texture.CombinerScale.One );

			terrain.setRenderState( ts );

			terrain.lock();

			rootNode.setRenderQueueMode( com.jme.renderer.Renderer.QUEUE_OPAQUE );
		} catch( Exception e ) {
			logger.logp(Level.SEVERE, this.getClass().toString(),
                    "simpleInitGame()", "Exception", e);
		}
	}
}